package com.vast.vastlcd.connection;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

import com.vast.vastlcd.lcdAPI.LCDDataInputStream;
import com.vast.vastlcd.lcdAPI.LCDDataOutputStream;
import com.vast.vastlcd.lcdAPI.LCDMessageHeader;

public class LCDSocketConnection implements IConnection {

	String hostAdress = ""; 
	Socket socket = null;
	int socketPortNum = 1977;
	
	LCDDataInputStream dataIn = null;
	LCDDataOutputStream dataOut = null;
	boolean createSocket = false;
	private byte[] msgHdrBuffer;
	
	/**
	 * @param hostAdress
	 * @param portNum
	 * @param createConnection
	 */
	public LCDSocketConnection(String hostAdress, int portNum, boolean createConnection) {
		this.hostAdress = hostAdress;
		socketPortNum = portNum; 	
		createSocket = createConnection;
		
		// If the Host Address is empty then we have to be creating a socket on 
		// the local host 
		if (hostAdress.equals("")) {
			if (!createConnection)
				System.out.println("Warning: As no host address was supplied, program will create socket.");
			createSocket = true;	
		}
		
	}
	
	public boolean connect() {
		if (createSocket) {
			ServerSocket servSock;
			try {
				servSock = new ServerSocket(socketPortNum);
				
				// Block until connection made
				socket = servSock.accept(); 
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}			
		}
		else {
			boolean notFound = true;
			while (notFound) {
				try {		
					socket = new Socket(hostAdress, socketPortNum);
					notFound = false;
				} catch (UnknownHostException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IOException e) {
					// Try to connect again after a delay
					try {
						Thread.sleep(200);
					} catch (InterruptedException e2) {
						e2.printStackTrace();
						return false;
					}
				}
			}
		}
		return true;
	}

	public boolean initialize() {
		try {
			dataIn = new LCDDataInputStream(socket.getInputStream());
			msgHdrBuffer = new byte[LCDMessageHeader.LCD_MSG_HDR_BYTE_SIZE];	
			//dataOut = new LCDDataOutputStream(socket.getOutputStream());
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		return true;
	}

	public boolean synchonize() {
		if (socket == null)
			return false;
			
		int bytesRead = 0;
		try {
			//System.out.println("avail: " + dataIn.available());
			while (dataIn.available() < LCDMessageHeader.LCD_MSG_HDR_BYTE_SIZE);
				;
				
				bytesRead = dataIn.read(msgHdrBuffer);
		} catch (IOException e) {
			e.printStackTrace();
			return false;
		}
		
		if (bytesRead == -1)
			return false;
				
		LCDMessageHeader msgHeader = LCDMessageHeader.nativeToJava(msgHdrBuffer);
		
		if ((msgHeader.nMessageLength > 0) && (msgHeader.nMessageType < LCDMessageHeader.LCD_REQ_MAX)) {
			//System.out.println("buffer size = " + msgHeader.nMessageLength);
			//System.out.println("type = " + msgHeader.nMessageType);
			byte[] msgBodyBuffer = new byte[msgHeader.nMessageLength];
			try {
				while (dataIn.available() < msgHeader.nMessageLength);
					;
				bytesRead = dataIn.read(msgBodyBuffer);
			} catch (IOException e) {
				e.printStackTrace();
				return false;
			}
			
			if (bytesRead == -1)
				bytesRead = 0; //System.out.println("bytes read equals -1");
			
			if (bytesRead != msgHeader.nMessageLength) {
				int bytesLeft = msgHeader.nMessageLength - bytesRead;
				try {
					while (dataIn.available() < bytesLeft);
						;
					
					dataIn.read(msgBodyBuffer, bytesRead, bytesLeft);
				} catch (IOException e) {
					e.printStackTrace();
					return false;
				}										
			}
			msgHeader.ProcessMessageHeader(msgBodyBuffer);
		}
		
		return true;
	}

}
